/* typehints:start */
import { Application } from "../application";
import { StateManager } from "./state_manager";
/* typehints:end */

import { createLogger, logSection } from "./utils/logging";
import { getObjectType, waitNextFrame } from "./utils/utils";
import { globalConfig } from "../config/global";
import { ClickDetector } from "./utils/click_detector";
import { MUSIC } from "./sound/interface";
import { ModalDialogs } from "./utils/modal_dialog";

const logger = createLogger('state');

export class State {
	constructor(key) {
		this.key = key;

		/** @type {Application} */
		this.app = null;

		/** @type {StateManager} */
		this.stateManager = null;

		/** @type {HTMLElement} */
		this.htmlElement = null;

		// 保存当前状态是否淡出
		this.fadingOut = false;

		/** @type {Array<ClickDetector>} */
		this.clickDetectors = [];
	}

	/**
	 * 返回状态key
	 * @returns {string}
	 */
	getKey() {
		return this.key;
	}

	/**
	 * 返回状态dom
	 * @returns {HTMLElement}
	 */
	getDivElement() {
		return document.getElementById("state_" + this.key);
	}

	/**
	 * 跳转状态
	 * @param {string} stateKey 
	 * @param {object} payload 
	 * @param {boolean} skipFadeOut 
	 * @returns 
	 */
	moveToState(stateKey, payload = {}, skipFadeOut = false) {
		if (this.fadingOut) {
			logger.warn("跳转<" + stateKey + ">失败，因为当前状态正在淡出。");
			return;
		}

		const fadeTime = this.internalGetFadeInOutTime();
		const doFade = !skipFadeOut && this.getHasFadeOut() && fadeTime !== 0;
		logger.log('跳转至', stateKey, `(fading=`, doFade,`)`);
		if(doFade){
			this.htmlElement.classList.remove("arrived");
			this.fadingOut = true;
			setTimeout(() => {
				this.stateManager.moveToState(stateKey, payload)
			}, fadeTime);
		} else{
			this.stateManager.moveToState(stateKey, payload);
		}
	}

  moveToStateAddGoBack(stateId){
    this.moveToState(stateId, {
      backToStateId: this.key,
      backToStatePayload: {
        backToStateId: this.backToStateId,
        backToStatePayload: this.backToStatePayload
      }
    })
  }

	trackClicks(element, handler, args = {}){
		const detector = new ClickDetector(element, args);
		detector.click.add(handler, this);
		if(G_IS_DEV){
			detector._src = 'state-' + this.key;
		}
		this.clickDetectors.push(detector);
	}

  mixin(arg){
    let type = getObjectType(arg);
    if(type !== 'Array') arg = [arg];

    arg.map(data => {
      Object.keys(data).map(key => {
        this[key] = data[key].bind(this);
      })
    })
  }

	/////////////////

	///  钩子函数  ///

  // 进入状态
	onEnter(payload) {}

  // 离开状态
	onLeave() {}

  // 第一次绘制
	onRender() {}

  // 尺寸发生变化
	onResized() {}

	// 关闭浏览器之前
  onBeforeExit(){}

	// 用户离开浏览器
	onAppPause(){}

	// 用户回到浏览器
	onAppResume(){}

  // 是否淡入
  getHasFadeIn(){
    return true;
  }

  // 是否淡出
  getHasFadeOut(){
    return true;
  }

	// 返回淡隐淡入的ms时间
	getInOutFadeTime() {
		return 200;
	}

  // 返回html代码
  getInnerHTML(){
    abstract;
    return "";
  }

  // 是否需要关闭页面确认是否关闭的通知
  getHasUnloadConfirmation(){
    return false;
  }

	// 是否播放背景音乐
	getThemeMusic(){
		return MUSIC.default;
	}

	/////////////////

	///  内部方法  ///

	internalGetFullHtml(){
		return this.getInnerHTML();
	}

	// 注册状态回调
	internalRegisterCallback(stateManager, app) {
		assert(stateManager, "没有找到状态管理器");
		assert(app, "没有找到App");
		this.stateManager = stateManager;
		this.app = app;
	}

	// 进入状态回调
	internalEnterCallback(payload, callCallback = true) {
		logSection(this.key, "#26a69a");

		this.htmlElement = this.getDivElement();
		this.htmlElement.classList.add("active");

		waitNextFrame().then(() => {
			if (this.htmlElement) {
				this.htmlElement.classList.remove("fadingOut");
				this.htmlElement.classList.remove("fadingIn");
			}
		});

		this.dialogs = new ModalDialogs(this.app);
		const dialogsElement = document.body.querySelector(".modalDialogParent");
		this.dialogs.initializeToElement(dialogsElement);

		if (callCallback) {
			this.onEnter(payload);
		}
	}

	// 离开状态回调
	internalLeaveCallback() {
		this.onLeave();

		this.htmlElement.classList.remove("active");
		this.internalCleanUpClickDetectors();
		this.dialogs.close();
	}

	/**
	 * 清除所有的事件监听
	 */
	internalCleanUpClickDetectors(){
		if(this.clickDetectors){
			for(let i = 0; i < this.clickDetectors.length; i++){
				this.clickDetectors[i].cleanup();
			}
			this.clickDetectors = [];
		}
	}

	// 离开页面的动画延迟
	internalGetFadeInOutTime() {
		if (G_IS_DEV && !globalConfig.debug.stateFadeInOutDelays) {
			return 1;
		}

		return this.getInOutFadeTime();
	}
}